spring-security简单使用与集成redis共享session(一)

一、搭建springboot项目

二、编写基础代码

1.Auth权限实体类

public class Auth implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 大模块code,例如咨询类功能
     */
    private String resourceCode;
    /**
     * 细化功能,例如查询咨询列表
     */
    private String actionCode;
    /**
     * 是否赋权
     */
    private String hasThisAuth;
    public Auth() {}
    public Auth(String resourceCode, String resourceName, String actionCode,
                String actionName, String actionURL, String remark,
                String hasThisAuth, String roleCombined) {
        this.resourceCode = resourceCode;
        this.actionCode = actionCode;
        this.hasThisAuth = hasThisAuth;
    }

    public String getResourceCode() {
        return resourceCode;
    }

    public void setResourceCode(String resourceCode) {
        this.resourceCode = resourceCode;
    }

    public String getActionCode() {
        return actionCode;
    }

    public void setActionCode(String actionCode) {
        this.actionCode = actionCode;
    }

    public String getHasThisAuth() {
        return hasThisAuth;
    }

    public void setHasThisAuth(String hasThisAuth) {
        this.hasThisAuth = hasThisAuth;
    }

}

2.Role角色实体类

public class Role implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 角色名称
     */
    private String name;
    /**
     * 角色code
     */
    private String code;

    /**
     * 拥有的权限列表
     */
    private List<Auth> auths;

    public Role() {
        // nothing
    }

    //region getter setter
    public List<Auth> getAuths() {
        return auths;
    }

    public void setAuths(List<Auth> auths) {
        this.auths = auths;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

}

3.CurrnetUser用户信息封装类

public class CurrentUser implements Serializable{

    private static final long serialVersionUID = 1L;
    private long id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 密码
     */
    private String password;
    /**
     * 部门
     */
    private String department;

    private Role role;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

}

4.UserAuthentication用户认证类

public class UserAuthentication implements Authentication {
    /**
     * 当前用户信息
     */
    private CurrentUser user;

    public UserAuthentication(CurrentUser user){
        if(user != null){
            this.user = user;
        }else{
            CurrentUser guest = new CurrentUser();
            this.user = guest;
        }
    }

    /**
     * 获取当前用户权限列表
     * 注:这里用户没有实际用到角色,代码中将角色也赋予成了权限
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();

        /**
         * 获取用户角色的对应的权限列表
         */
        if(user.getRole() != null){
            Role userRole = user.getRole();

            // add "AUTH" 规则:ResourceCode:ActionCode
            for(Auth userAuth : userRole.getAuths()){

                // "1" - has this auth | "0" - do not have this auth
                if("1".equals(userAuth.getHasThisAuth())){
                    GrantedAuthority mainAuth = (GrantedAuthority) ()
                            -> userAuth.getResourceCode() + ":" + userAuth.getActionCode();
                    authorities.add(mainAuth);
                }
            }

            // add "ROLE" 规则 ROLE_code
            GrantedAuthority mainAuth = (GrantedAuthority) ()
                    -> "ROLE_" + userRole.getCode();
            authorities.add(mainAuth);
        }

        return authorities;
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getDetails() {
        return null;
    }

    @Override
    public CurrentUser getPrincipal() {
        return user;
    }

    @Override
    public boolean isAuthenticated() {
        return true;
    }

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

    }

    @Override
    public String getName() {
        return user.getName() == null ? "guest" : user.getName();
    }
}

5.ApiBaseMessage通用返回信息类

@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiBaseMessage<T> {

    private boolean success;
    private String statusCode = "";
    private T data;
    private String error = "";

    public ApiBaseMessage(){

    }

    // constructor for success and data
    public ApiBaseMessage(T data){
        this.success = true;
        this.data =  data;
    }

    // constructor for app server error message
    public ApiBaseMessage(String statusCode, String errorDescribe){
        this.statusCode = statusCode;
        this.error = errorDescribe;
    }

    // constructor from a failed ApiBaseMessage
    public ApiBaseMessage(ApiBaseMessage<?> msg) {
        this.statusCode = msg.getStatusCode();
        this.error = msg.getError();
        this.success = false;
        this.data = null;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(String statusCode) {
        this.statusCode = statusCode;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

    @Override
    public String toString() {
        return "ApiBaseMessage{" +
                "success=" + success +
                ", statusCode='" + statusCode + '\'' +
                ", data=" + data +
                ", error='" + error + '\'' +
                '}';
    }
}

6.Controller层代码编写

@RestController
@RequestMapping(value = "/api/service/account")
public class UserController {

    /**
     * 登录功能
     * @return
     */
    @RequestMapping(value = "/login", method = {RequestMethod.GET})
    public ApiBaseMessage login(){
        //TODO 调用第三方权限认证接口

        /**
         * 用户信息
         */
        CurrentUser currentUser = new CurrentUser();
        currentUser.setName("王坤");
        currentUser.setDepartment("研发部");

        /**
         * 权限信息
         */
        List<Auth> auths = new ArrayList<>();
        Auth auth = new Auth();
        auth.setResourceCode("userinfo");
        auth.setActionCode("query");
        auth.setHasThisAuth("1");
        auths.add(auth);

        /**
         * 角色信息
         */
        Role role = new Role();
        role.setAuths(auths);
        currentUser.setRole(role);

        SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(currentUser));
        return new ApiBaseMessage("登录成功");
    }

    /**
     * 查询功能
     * @return
     */
    @RequestMapping(value = "/query", method = {RequestMethod.GET})
    public ApiBaseMessage query(){
        /**
         * 获取登录用户信息
         */
        CurrentUser principal = (CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        return new ApiBaseMessage("查询成功,亲爱的"+principal.getName());
    }
}

三、配置权限信息

创建SecurityConfig权限配置类
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // csrf 关闭,保证 api 调用无须传递 csrf token
//        http.antMatcher("/api/**")
//                .csrf().disable().
                http.authorizeRequests()
                        .antMatchers("/api/service/account/login").permitAll()//这些请求放行,通常是登录请求和不需要登录就能调用的接口
                        .antMatchers("/api/service/account/query").hasAuthority("userinfo:query")//需要相关的权限
                        .anyRequest().authenticated()//其他请求校验
                        .and()//并且 如下校验
                        .exceptionHandling().authenticationEntryPoint((request, response, authException) -> {//异常处理,当匿名登录被拦截时走的方法
                                ObjectMapper mapper = new ObjectMapper();
                                String errorMsg;
                                if (request.getRequestURI().startsWith("/api/internal/")) {
                                    errorMsg = mapper.writeValueAsString(new ApiBaseMessage<>("10002", "非法的请求来源:" + request.getRemoteHost()));
                                } else {
                                    errorMsg = mapper.writeValueAsString(new ApiBaseMessage<>("10002", "请先登录"));
                                }
                                response.setContentType("application/json");
                                response.setStatus(HttpServletResponse.SC_OK);
                                response.setCharacterEncoding("UTF-8");
                                response.getWriter().write(errorMsg);
                        })
                ;

        // 子线程继承父线程 spring security context
        //SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    }

}

四、测试

按照第三步配置,预期情况如下:

1.直接调用query接口,提示请登录

2.调用登录接口成功后,再次调用query接口能成功,并且能读取到登录用户的信息

启动项目,开始测试:

http://localhost:8082/api/service/account/query

http://localhost:8082/api/service/account/login

http://localhost:8082/api/service/account/query

测试通过。

后续小伙伴可以把登录接口中 权限设置为0,再试试,或者把SecurityConfig类,对于query接口的权限进行更改再进行相关测试。

五、集成spring session 和 redis,完成分布式session共享,解决集群模式下身份认证信息无法共享的问题

参考第二篇博客

https://blog.csdn.net/wk2yangyang/article/details/118541553

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值