Explorar o código

增加token鉴权

xiongzhu %!s(int64=7) %!d(string=hai) anos
pai
achega
c551895244

+ 13 - 0
src/main/java/com/izouma/awesomeadmin/activiti/RestFilter.java

@@ -11,6 +11,8 @@ import org.springframework.web.filter.GenericFilterBean;
 
 import javax.servlet.*;
 import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
 @WebFilter
@@ -27,6 +29,17 @@ public class RestFilter extends GenericFilterBean {
         } catch (Exception e) {
             e.printStackTrace();
         }
+        try {
+            HttpServletRequest request = (HttpServletRequest) servletRequest;
+            HttpServletResponse response = (HttpServletResponse) servletResponse;
+            response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
+            response.addHeader("Access-Control-Allow-Methods", "*");
+            response.addHeader("Access-Control-Max-Age", "100");
+            response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
+            response.addHeader("Access-Control-Allow-Credentials", "true");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
         filterChain.doFilter(servletRequest, servletResponse);
     }
 }

+ 2 - 0
src/main/java/com/izouma/awesomeadmin/dao/SysAppTokenMapper.java

@@ -9,4 +9,6 @@ public interface SysAppTokenMapper {
     AppToken getToken(String token);
 
     int delToken(String token);
+
+    int delUserToken(Integer userId);
 }

+ 3 - 0
src/main/java/com/izouma/awesomeadmin/dao/SysAppTokenMapper.xml

@@ -8,6 +8,9 @@
     <delete id="delToken">
         delete from sys_app_token where token = #{token}
     </delete>
+    <delete id="delUserToken">
+        delete from sys_app_token where user_id = #{userId}
+    </delete>
     <select id="getToken" resultType="com.izouma.awesomeadmin.shiro.AppToken">
         select * from sys_app_token where token = #{token}
     </select>

+ 102 - 9
src/main/java/com/izouma/awesomeadmin/web/AuthenticationController.java

@@ -1,38 +1,44 @@
 package com.izouma.awesomeadmin.web;
 
-import com.google.common.collect.Maps;
+import com.izouma.awesomeadmin.dao.SysAppTokenMapper;
 import com.izouma.awesomeadmin.dto.Result;
 import com.izouma.awesomeadmin.model.UserInfo;
+import com.izouma.awesomeadmin.shiro.PhoneCodeToken;
+import com.izouma.awesomeadmin.util.CookieUtil;
 import com.izouma.awesomeadmin.util.PropertiesFileLoader;
 import com.izouma.awesomeadmin.util.VerifyCodeUtils;
-import io.jsonwebtoken.CompressionCodecs;
 import io.jsonwebtoken.JwtBuilder;
 import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
 import io.jsonwebtoken.security.Keys;
 import org.apache.commons.lang.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.annotation.RequiresAuthentication;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
 
 import javax.crypto.SecretKey;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
-import javax.xml.bind.DatatypeConverter;
 import java.io.IOException;
-import java.util.Base64;
-import java.util.Date;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
 
 @Controller
 @RequestMapping("/auth")
 public class AuthenticationController {
 
-    private final String SECRET_KEY = "*(-=4eklfasdfarerf41585fdasf";
+    @Autowired
+    private SysAppTokenMapper sysAppTokenMapper;
 
     @RequestMapping(value = "/image", method = RequestMethod.GET)
     @ResponseBody
@@ -58,5 +64,92 @@ public class AuthenticationController {
         return new Result(false, "验证图片生成失败");
     }
 
+    @RequestMapping(value = "/login", method = RequestMethod.POST)
+    @ResponseBody
+    public ModelAndView login(@RequestParam("username") String username,
+                              @RequestParam("password") String password,
+                              @RequestParam(value = "remember", required = false, defaultValue = "false") boolean remember,
+                              @RequestParam(value = "requireToken", required = false, defaultValue = "false") boolean requireToken,
+                              HttpServletResponse response,
+                              HttpServletRequest request) {
+        ModelAndView result = new ModelAndView(new MappingJackson2JsonView());
+        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
+        Map<String, Object> map = login(usernamePasswordToken, remember, requireToken, 3, request, response);
+        result.addAllObjects(map);
+        return result;
+    }
+
+    @RequestMapping(value = "/loginSms", method = RequestMethod.POST)
+    @ResponseBody
+    public ModelAndView loginBySms(@RequestParam("phone") String phone,
+                                   @RequestParam("code") String code,
+                                   @RequestParam("sessionId") String sessionId,
+                                   @RequestParam(value = "remember", required = false, defaultValue = "false") boolean remember,
+                                   @RequestParam(value = "requireToken", required = false, defaultValue = "false") boolean requireToken,
+                                   HttpServletRequest request,
+                                   HttpServletResponse response) {
+        ModelAndView result = new ModelAndView(new MappingJackson2JsonView());
+        PhoneCodeToken phoneCodeToken = new PhoneCodeToken(phone, code, sessionId);
+        Map<String, Object> map = login(phoneCodeToken, remember, requireToken, 3, request, response);
+        result.addAllObjects(map);
+        return result;
+    }
 
+    @RequiresAuthentication
+    @RequestMapping(value = "/logout", method = RequestMethod.POST)
+    @ResponseBody
+    public Result logout(String token) {
+        if (StringUtils.isNotEmpty(token)) {
+            sysAppTokenMapper.delToken(token);
+        }
+        Subject subject = SecurityUtils.getSubject();
+        subject.logout();
+        return new Result(true, "已退出登录");
+    }
+
+    private Map<String, Object> login(AuthenticationToken authenticationToken, boolean remember, boolean requireToken,
+                                      int expireDays, HttpServletRequest request, HttpServletResponse response) {
+        Map<String, Object> map = new HashMap<>();
+        Subject subject = SecurityUtils.getSubject();
+        try {
+            subject.login(authenticationToken);
+        } catch (AuthenticationException e) {
+            e.printStackTrace();
+            map.put("success", false);
+            map.put("error", e.getMessage());
+            return map;
+        }
+        UserInfo user = (UserInfo) subject.getPrincipal();
+        if (remember) {
+            HttpSession session = request.getSession();
+            CookieUtil.addCookie(response, "JSESSIONID", session.getId(), expireDays * 24 * 60 * 60);
+        }
+        if (requireToken) {
+            String token = createToken(user, expireDays, false);
+            map.put("token", token);
+        }
+        map.put("success", true);
+        map.put("data", user);
+        return map;
+    }
+
+    private String createToken(UserInfo userInfo, int expireDays, boolean kickOut) {
+        if (kickOut) {
+            sysAppTokenMapper.delUserToken(userInfo.getId());
+        }
+        SecretKey key = Keys.hmacShaKeyFor(Base64.getDecoder().decode(PropertiesFileLoader.getProperties("jwtsecret").getBytes()));
+        JwtBuilder jwt = Jwts.builder();
+        jwt.setId(UUID.randomUUID().toString())
+                .setIssuer("admin")
+                .setIssuedAt(new Date())
+                .setSubject(userInfo.getId().toString())
+                .signWith(key);
+        if (expireDays > 0) {
+            Date date = new Date(System.currentTimeMillis() + (expireDays * 24 * 60 * 60 * 1000));
+            jwt.setExpiration(date);
+        }
+        String token = jwt.compact();
+        sysAppTokenMapper.saveToken(userInfo.getId(), token);
+        return token;
+    }
 }

+ 0 - 101
src/main/java/com/izouma/awesomeadmin/web/UserInfoController.java

@@ -190,106 +190,5 @@ public class UserInfoController {
         ExportExcelUtil.ExportWithResponse(sheetName, titleName, fileName,
                 columnNumber, columnWidth, columnName, dataList, response);
     }
-
-    @RequestMapping(value = "/login", method = RequestMethod.POST)
-    @ResponseBody
-    public Result login(@RequestParam("username") String username, @RequestParam("password") String password,
-                        @RequestParam(value = "remember", required = false, defaultValue = "false") boolean remember,
-                        HttpServletResponse response, HttpServletRequest request) {
-        Subject subject = SecurityUtils.getSubject();//获取当前用户对象
-        //生成令牌(传入用户输入的账号和密码)
-        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
-        //认证登录
-        try {
-            //这里会加载自定义的realm
-            subject.login(token);//把令牌放到login里面进行查询,如果查询账号和密码时候匹配,如果匹配就把user对象获取出来,失败就抛异常
-            UserInfo user = (UserInfo) subject.getPrincipal();//获取登录成功的用户对象(以前是直接去service里面查)
-            request.getSession(true).setAttribute("superUserId", String.valueOf(user.getId()));
-            if (remember) {
-                HttpSession session = request.getSession();
-                CookieUtil.addCookie(response, "JSESSIONID", session.getId(), 3 * 24 * 60 * 60);
-            }
-            return new Result(true, "登录成功");
-        } catch (AuthenticationException e) {
-            e.printStackTrace();
-            return new Result(false, "登录失败");
-        }
-    }
-
-    @RequestMapping(value = "/loginSms", method = RequestMethod.POST)
-    @ResponseBody
-    public Result loginBySms(@RequestParam("phone") String phone, @RequestParam("code") String code, @RequestParam("sessionId") String sessionId, HttpServletRequest request, HttpServletResponse response) {
-        Subject subject = SecurityUtils.getSubject();
-        PhoneCodeToken phoneCodeToken = new PhoneCodeToken(phone, code, sessionId);
-        try {
-            subject.login(phoneCodeToken);
-        } catch (AuthenticationException e) {
-            e.printStackTrace();
-            return new Result(false, e.getMessage());
-        }
-        UserInfo user = (UserInfo) subject.getPrincipal();
-        HttpSession session = request.getSession();
-        CookieUtil.addCookie(response, "JSESSIONID", session.getId(), 3 * 24 * 60 * 60);
-        return new Result(true, user);
-    }
-
-    @RequiresAuthentication
-    @RequestMapping(value = "/logout", method = RequestMethod.POST)
-    @ResponseBody
-    public Result logout() {
-
-        Subject subject = SecurityUtils.getSubject();
-        subject.logout();
-        return new Result(true, "已退出登录");
-    }
-
-
-    @RequestMapping(value = "/departInfoTree", method = RequestMethod.GET)
-    @ResponseBody
-    public Result departInfoTree(HttpServletRequest request, Page page, DepartInfo record, Integer includeParent) {
-        Map<String, Object> result = new HashMap<>();
-        //根据登录权限查看用户信息
-        String userId = (String) request.getSession().getAttribute("superUserId");
-        UserInfo userInfo = userInfoService.getUserInfoById(userId);
-        String[] deptCodes = userInfo.getDepartId().split(",");
-        DepartInfo departInfo = departInfoService.getDepartInfoById(deptCodes[deptCodes.length - 1]);
-        List<DepartInfo> pp = departInfoService.getDepartInfoList(record);
-        if (includeParent != null && includeParent == 1) {
-            pp.addAll(departInfoService.getParentList(departInfo.getId()));
-        }
-
-        List<TreeNode> trees = new ArrayList<TreeNode>();
-        List<TreeNode> tree = new ArrayList<TreeNode>();
-        for (DepartInfo m : pp) {
-            String[] leafs;
-            if (m.getAllParentId() != null) {
-                leafs = m.getAllParentId().split(",");
-            } else {
-                leafs = new String[0];
-            }
-            TreeNode treeNode = new TreeNode(m.getId() + "", m.getDepartName(), leafs.length == 0 ? "" : leafs[leafs.length - 1]);
-            treeNode.setExtra(m.getId().toString());
-            tree.add(treeNode);
-
-
-        }
-        for (TreeNode treeNode : tree) {
-            if ("".equals(treeNode.getParentId())
-                    || (record.getId().equals(treeNode.getId()) && (includeParent == null || includeParent == 0))) {
-                trees.add(treeNode);
-            }
-            for (TreeNode it : tree) {
-                if (it.getParentId().equals(treeNode.getId())) {
-                    if (treeNode.getChildren() == null) {
-                        treeNode.setChildren(new ArrayList<TreeNode>());
-                    }
-                    treeNode.getChildren().add(it);
-                }
-            }
-        }
-
-        result.put("pp", trees);
-        return new Result(true, result);
-    }
 }
 

+ 2 - 2
src/main/vue/src/main.js

@@ -66,7 +66,7 @@ Vue.prototype.$http = {
                     if (res.data.code === 10001) {
                         axios({
                             method: 'post',
-                            url: '/userInfo/logout'
+                            url: '/auth/logout'
                         });
                         store.commit('updateUserInfo', null);
                         router.replace('/login');
@@ -133,7 +133,7 @@ Vue.prototype.$http = {
                     if (res.data.code === 10001) {
                         axios({
                             method: 'post',
-                            url: '/userInfo/logout'
+                            url: '/auth/logout'
                         });
                         store.commit('updateUserInfo', null);
                         router.replace('/login');

+ 1 - 1
src/main/vue/src/pages/App.vue

@@ -129,7 +129,7 @@
             onCommand(command) {
                 if (command === 'logout') {
                     this.$http.post({
-                        url: '/userInfo/logout'
+                        url: '/auth/logout'
                     }).then(res => {
                         if (res.success) {
                             this.$store.commit('updateUserInfo', null);

+ 66 - 65
src/main/vue/src/pages/Login.vue

@@ -20,76 +20,77 @@
     </div>
 </template>
 <script>
-export default {
-    data() {
-        return {
-            rememberMe: false,
-            loading: false,
-            userInfo: {
-                username: '',
-                password: ''
-            }
-        }
-    },
-    methods: {
-        login() {
-            this.$refs.form.validate(valid => {
-                if (valid) {
-                    this.loading = true;
-                    this.$http.post({
-                        url: '/userInfo/login',
-                        data: {
-                            username: this.userInfo.username,
-                            password: this.userInfo.password,
-                            remember: this.rememberMe
-                        }
-                    }).then(res => {
-                        this.loading = false;
-                        if (res.success) {
-                            this.$router.replace('/');
-                        } else {
-                            this.$message.error('登录失败');
-                        }
-                    }).catch(() => {
-                        this.loading = false;
-                    })
+    export default {
+        data() {
+            return {
+                rememberMe: false,
+                loading: false,
+                userInfo: {
+                    username: '',
+                    password: ''
                 }
-            })
+            }
+        },
+        methods: {
+            login() {
+                this.$refs.form.validate(valid => {
+                    if (valid) {
+                        this.loading = true;
+                        this.$http.post({
+                            url: '/auth/login',
+                            data: {
+                                username: this.userInfo.username,
+                                password: this.userInfo.password,
+                                remember: this.rememberMe,
+                                requireToken: true
+                            }
+                        }).then(res => {
+                            this.loading = false;
+                            if (res.success) {
+                                this.$router.replace('/');
+                            } else {
+                                this.$message.error('登录失败');
+                            }
+                        }).catch(() => {
+                            this.loading = false;
+                        })
+                    }
+                })
+            }
         }
     }
-}
 </script>
 <style lang="less" scoped>
-.container {
-    width: 100%;
-    height: 100%;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background-color: #ebebeb;
-    background-image: url('https://microball.oss-cn-hangzhou.aliyuncs.com/izouma/application/rawpixel-com-565462-unsplash%20%281%29.jpg');
-    background-size: cover;
-    background-position: center;
-    background-repeat: no-repeat;
-}
+    .container {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background-color: #ebebeb;
+        background-image: url('https://microball.oss-cn-hangzhou.aliyuncs.com/izouma/application/rawpixel-com-565462-unsplash%20%281%29.jpg');
+        background-size: cover;
+        background-position: center;
+        background-repeat: no-repeat;
+    }
 
-.login-wrapper {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    border-radius: 5px;
-    background: white;
-    border: 1px #eaeaea solid;
-    position: absolute;
-    right: 100px;
-    top: 100px;
-    width: 400px;
-    .title {
-        color: #20a0ff;
-        font-weight: bold;
-        width: 350px;
-        line-height: 60px;
+    .login-wrapper {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        border-radius: 5px;
+        background: white;
+        border: 1px #eaeaea solid;
+        position: absolute;
+        right: 100px;
+        top: 100px;
+        width: 400px;
+        .title {
+            color: #20a0ff;
+            font-weight: bold;
+            width: 350px;
+            line-height: 60px;
+        }
     }
-}
 </style>

+ 2 - 8
src/main/webapp/WEB-INF/web.xml

@@ -3,19 +3,13 @@
          xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          id="WebApp_ID" version="3.0">
-
+    <display-name>awesome-admin</display-name>
     <welcome-file-list>
-        <welcome-file>index.html</welcome-file>
+        <welcome-file>/admin</welcome-file>
     </welcome-file-list>
-
     <session-config>
         <session-timeout>30</session-timeout>
     </session-config>
-
-    <display-name>awesome-admin</display-name>
-    <welcome-file-list>
-        <welcome-file>admin</welcome-file>
-    </welcome-file-list>
     <context-param>
         <param-name>log4jConfigLocation</param-name>
         <param-value>classpath:properties/log4j.properties</param-value>